package com.xiaoma.myaudience.util;

import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

import android.util.Log;

public class ReflectUtils {
    final static String TAG = "ReflectUtil";
    
	public static void printAllInform(Class clsShow) {
		try {
			// get all methods
			Method[] hideMethod = clsShow.getMethods();
			int i = 0;
			final StringBuilder sb = new StringBuilder();
			for (; i < hideMethod.length; i++) {
			    sb.delete(0, sb.length());
				sb.append(hideMethod[i].getName()).append("(");

				Class[] parameterTypes = hideMethod[i].getParameterTypes();
				for (int j = 0; j < parameterTypes.length; j++) {
					sb.append(parameterTypes[j].getName()).append(",");
				}
				sb.append(")");
				Log.e(TAG, "method name " + sb.toString());

			}
			// get all filed
			Field[] allFields = clsShow.getFields();
			for (i = 0; i < allFields.length; i++) {
				Log.e(TAG, "Field name:" + allFields[i].getName());
			}
		} catch (SecurityException e) {
			// throw new RuntimeException(e.getMessage());
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// throw new RuntimeException(e.getMessage());
			e.printStackTrace();
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}

    public static Object getValue(Object object, String fieldName) throws IllegalAccessException,
            NoSuchFieldException {
        Field field = getField(object.getClass(), fieldName);
        return field.get(object);
    }
	
    public static Object getValue(String className, String fieldName) throws Exception {
        return getValue(Class.forName(className), fieldName);
    }

    public static Object getValue(Class clazz, String fieldName) throws IllegalAccessException,
            NoSuchFieldException {
        Field field = getField(clazz, fieldName);
        return field.get(null);
    }

	

	public static Field getField(Class clazz, String fieldName)
			throws NoSuchFieldException {

		if (clazz == null || clazz == Object.class) {
			throw new NoSuchFieldException("field not found: " + fieldName);
		}
		Field field;
		try {
			field = clazz.getDeclaredField(fieldName);
		} catch (NoSuchFieldException nsfe) {
			field = getField(clazz, clazz.getSuperclass(), fieldName);
		}
		field.setAccessible(true);

		if (clazz == null) {
			throw new NoSuchFieldException("Error field !");
		}
		return field;
	}

	private static Field getField(Class root, Class clazz, String fieldName)
			throws NoSuchFieldException {
		if (clazz == null || clazz == Object.class) {
			throw new NoSuchFieldException("field [" + fieldName
					+ "] not found on " + root.getName());
		}
		Field field;
		try {
			field = clazz.getDeclaredField(fieldName);
		} catch (NoSuchFieldException nsfe) {
			field = getField(root, clazz.getSuperclass(), fieldName);
		}
		return field;
	}

	public static Method getMethod(Object instance, String methodName)
			throws NoSuchMethodException {
	    return getMethod(instance.getClass(), methodName, null);
	}

	public static Method getMethod(Object instance, String methodName,
			Class[] classTypes) throws NoSuchMethodException {
		return getMethod(instance.getClass(), methodName, classTypes);
	}

	private static Method getMethod(Class thisClass, String methodName,
			Class[] classTypes) throws NoSuchMethodException {
		if (thisClass == null) {
			throw new NoSuchMethodException(" Error method ! ");
		}
		try { 
			Method accessMethod = thisClass.getDeclaredMethod(methodName, classTypes);
			accessMethod.setAccessible(true);
			return accessMethod;
		} catch (Exception e) {
		    StringBuilder sb = new StringBuilder("can't not find ").append(methodName).append("(");
            for (Class clazz : classTypes) {
                sb.append(clazz.toString()).append(",");
            }
            sb.append(") in ").append(thisClass.toString());
            Log.e(TAG, sb.toString());
		    return getMethod(thisClass.getSuperclass(), methodName, classTypes);
		}
	}

	public static Object invokeMethod(Object instance, String methodName)
			throws NoSuchMethodException, IllegalAccessException,
			InvocationTargetException {
		return invokeMethod(instance, methodName, null);
	}

	public static Object invokeMethod(Object instance, String methodName,
			Object arg) throws NoSuchMethodException, IllegalAccessException,
			InvocationTargetException {

		Object[] args = null;
		if (arg != null) {
			args = new Object[1];
			args[0] = arg;
		}

		return invokeMethod(instance, methodName, args);
	}

	public static Object invokeMethod(Object instance, String methodName,
			Object[] args) throws NoSuchMethodException,
			IllegalAccessException, InvocationTargetException {
		Class[] classTypes = null;
		if (args != null) {
			classTypes = new Class[args.length];
			for (int i = 0; i < args.length; i++) {
				if (args[i] != null) {
					classTypes[i] = args[i].getClass();
				}
			}
		}
		return invokeMethod(instance, methodName, args, classTypes);
	}

	

	public static Object invokeMethod(Class clazz, String methodName,
			Object arg, Class classType) throws NoSuchMethodException,
			IllegalAccessException, InvocationTargetException,
			InstantiationException {
		return invokeMethod(clazz, methodName, new Object[]{arg}, new Class[]{classType});
	}
	
	public static Object invokeMethod(Object instance, String methodName,
            Object arg, Class classType) throws NoSuchMethodException,
            IllegalAccessException, InvocationTargetException {
        return invokeMethod(instance, methodName, new Object[]{arg}, new Class[]{classType});
    }

	public static Object invokeMethod(Class clazz, String methodName,
			Object[] args, Class[] classTypes) throws NoSuchMethodException,
			IllegalAccessException, InvocationTargetException,
			InstantiationException {
		return invokeMethod(getInstance(clazz), methodName, args, classTypes);
	}
	
	public static Object invokeMethod(Object instance, String methodName,
            Object[] args, Class[] classTypes) throws NoSuchMethodException,
            IllegalAccessException, InvocationTargetException {
        return getMethod(instance, methodName, classTypes).invoke(instance,
                args);
    }
	
	public static Object getInstance(Class clazz) throws IllegalAccessException, InstantiationException {
	    return clazz.newInstance();
	}
	
	public static Object getInstance(String className) throws IllegalAccessException, InstantiationException, ClassNotFoundException {
        return getInstance(Class.forName(className));
    }
	
	   
    public static Object getInstance(String className, Object[] args, Class[] classTypes) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException, ClassNotFoundException {
        Class clazz = Class.forName(className);
        return getInstance(clazz, args, classTypes);
    }
	
	public static Object getInstance(Class clazz, Object[] args) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
	    Class[] classTypes = null;
        if (args != null) {
            classTypes = new Class[args.length];
            for (int i = 0; i < args.length; i++) {
                if (args[i] != null) {
                    classTypes[i] = args[i].getClass();
                }
            }
        }
        return getInstance(clazz, args, classTypes);
    }
	
	public static Object getInstance(Class clazz, Object[] args, Class[] classTypes) throws SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetException {
        if (classTypes == null) {
            return getInstance(clazz);
        } else {
            Constructor constructor = clazz.getConstructor(classTypes);
            return constructor.newInstance(args);
        }
	}
	
	public static Object invokeStaticMethod(String className,
			String methodName, Object[] args) throws Exception {
		return invokeStaticMethod(Class.forName(className), methodName, args);
	}

	public static Object invokeStaticMethod(Class clazz, String methodName,
			Object[] args) throws Exception {

		Class[] argsClass = new Class[args.length];

		for (int i = 0, j = args.length; i < j; i++) {
			argsClass[i] = args[i].getClass();
		}

		return invokeStaticMethod(clazz, methodName, args, argsClass);
	}
	
    
    public static Object invokeStaticMethod(String className,
            String methodName, Object[] args, Class[] argsClass) throws Exception {
        return invokeStaticMethod(Class.forName(className), methodName, args, argsClass);
    }
	
    public static Object invokeStaticMethod(Class clazz,
            String methodName, Object[] args, Class[] argsClass) throws Exception {
        Method method = clazz.getMethod(methodName, argsClass);
        return method.invoke(null, args);
    }
}
